Skip to content

feat: automatically obtain TLS certificate for /wss listener#8740

Draft
marten-seemann wants to merge 3 commits intomasterfrom
certmanager
Draft

feat: automatically obtain TLS certificate for /wss listener#8740
marten-seemann wants to merge 3 commits intomasterfrom
certmanager

Conversation

@marten-seemann
Copy link
Member

@marten-seemann marten-seemann commented Feb 17, 2022

With this change, users can easily offer WSS support on their IPFS nodes. libp2p will then use ACME to obtain a TLS certificate for the domain.

Configuration: the user needs to configure a wss listen address in Addresses.Swarm to enable secure websockets support.

In the long term, we might be able to get rid of the AppendAnnounces configuration, but this will require some refactoring in go-libp2p. go-libp2p is currently super eager to resolve all addresses immediately, but the TLS server in websockets actually needs the FQDN to be able to select the correct certificate.


Update 2022-02-21: Addresses.AppendAnnounce is not needed any more.

Copy link
Member

@lidel lidel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removing the need for nginx for /wss is a significant improvement!
Can't wait for this to land ❤️

Only one caveat: how does the ACME challenge work next to HTTP gateway?

  • When I add /dns4/example.com/tcp/1234/wss to Addresses.Swarm will it temporarily start HTTP listener on /dns4/example.com/tcp/80/ for HTTP Challenge?
    • This may be problematic for go-ipfs users because they already run HTTP server of some sort on ports 80 and 443 (either go-ipfs itself, or a reverse proxy like nginx).
    • Should we detect when ACME challenge port is taken by something else, and pick some other localhost port + print warning asking user to manually mount http://127.0.0.1:<alternative-acme-challenge-port>/.well-known/acme-challenge/ under https://example.com/.well-known/acme-challenge/? This should be an acceptable solution for existing nginx users.
      • I feel we may need the ability to set <alternative-acme-challenge-port> via go-ipfs-config for better determinism.
      • If we can use go-ipfs-config, could we pass static cert and use that instead of ACME?

@marten-seemann
Copy link
Member Author

If we can use go-ipfs-config, could we pass static cert and use that instead of ACME?

Yes. The CertManager has a method for that, see https://github.com/marten-seemann/go-libp2p-certbot#manual-certificate-management. You'd have to call that instead of https://github.com/ipfs/go-ipfs/blob/6589293eb8cafc898972ff102ad0b1ef5ad2d3d9/core/node/libp2p/transport.go#L35, so that should be very easy to implement. Regarding the wiring up required with the IPFS config, it would be great if the IPFS stewards could take up that work though, as I'm sure you guys will have strong opinions on how this new config option would look like :)

This may be problematic for go-ipfs users because they already run HTTP server of some sort on ports 80 and 443 (either go-ipfs itself, or a reverse proxy like nginx).

It it's a Go HTTP server, we could just attach to that one, right? Users could pass their http.ServeMux to the certbot. Is that something we want to support?

Should we detect when ACME challenge port is taken by something else, and pick some other localhost port + print warning asking user to manually mount http://127.0.0.1:/.well-known/acme-challenge/ under https://example.com/.well-known/acme-challenge/? This should be an acceptable solution for existing nginx users.

Yes, let me figure out how to do that with certmagic.

@thattommyhall
Copy link
Member

thattommyhall commented Feb 20, 2022

Excited to see this, I was thinking the same a little while back.

I was going to help a mate do something like https://words.filippo.io/how-plex-is-doing-https-for-all-its-users/ for his app, and I was wondering if it would be useful for folk to have a cert for, say, *.<PEERID>.peer.id in libp2p land using the same trick? We'd need some extra cryptography to attest it was definity the peer that did it or something.

I have a proof of concept that uses auth0 to identify you on twitter, you pass the app the TXT challenge so ACME can issue you a cert for say *.thattommyhall.sslify.me , and some PowerDNS scripting to serve up 1.2.3.4 for 1-2-3-.thattommyhall.sslify.me and fetch the txt challenge from S3 so you can verify the DNS.

Prior art for just issuing SSL certs for an IP was https://sslip.io/ https://nip.io/

@aschmahmann
Copy link
Contributor

@thattommyhall take a look at libp2p/go-libp2p#1331.

TLDR: I suspect we'll want some mechanism to auto-grant people TLS certs so they can support WSS, but a step at a time especially because a bunch of the issues with granting certs are political rather than technological (e.g. one could easily imagine a world where *.peer.id's cert was secured by the peerID itself rather than some CA... but that's an uphill battle) so it might take some time. Those are some great links though 🙏

@marten-seemann marten-seemann changed the title WIP: automatically obtain TLS certificate for Secure WebSockets automatically obtain TLS certificate for Secure WebSockets Feb 21, 2022
@marten-seemann
Copy link
Member Author

@thattommyhall Thank you for these links, those are very interesting reads! It's out of scope for this PR, let's get the simplest option up and running.

I updated this PR, mostly to update the dependencies. Big win: It's not necessary any more to add an address to AppendAnnounces, just adding a /dns address to Swarm.Addresses is sufficient now (thanks to libp2p/go-ws-transport#117).

Copy link
Member

@lidel lidel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is excellent news! Remaining questions:

  • What happens when port 80(?) (used for HTTP-01 challenge) is taken?
    • log Error and continue without /wss ? (sounds fine for mvp)
  • How to support manual key setup?
    • The manual setup will be pretty niche and elaborate, so little value in exposing this via config. What if we do the same thing we did for private swarm and if one adds /dns/example.net/.../wss addr, check if $IPFS_PATH/example.net.crt and $IPFS_PATH/example.net.key exist and use them if present? (and if not, do ACME)

@lidel lidel changed the title automatically obtain TLS certificate for Secure WebSockets feat: automatically obtain TLS certificate for /wss listener Feb 24, 2022
@marten-seemann marten-seemann force-pushed the update-libp2p-v018 branch 3 times, most recently from 293ceaf to b9f0052 Compare March 4, 2022 10:16
@BigLep BigLep marked this pull request as draft March 10, 2022 09:34
@BigLep BigLep added this to the Best Effort Track milestone Mar 10, 2022
@BigLep
Copy link
Contributor

BigLep commented Mar 10, 2022

@marten-seemann : I moved this back to draft given feedback from @lidel to incorporate. Pease mark as "Ready for review" when it should be looked at again.

Thanks again for doing this - good stuff!

@marten-seemann marten-seemann force-pushed the update-libp2p-v018 branch 3 times, most recently from 33fbdbf to 26b8c42 Compare March 18, 2022 08:03
@lidel lidel force-pushed the update-libp2p-v018 branch from 26b8c42 to 859e648 Compare April 2, 2022 00:07
Base automatically changed from update-libp2p-v018 to master April 8, 2022 01:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

No open projects
Status: 🔎 In Review

Development

Successfully merging this pull request may close these issues.

5 participants